package org.restoran.model;


import org.codehaus.jackson.annotate.JsonProperty;
import org.codehaus.jackson.map.annotate.JsonDeserialize;
import org.codehaus.jackson.map.annotate.JsonSerialize;
import org.restoran.service.parser.jackson.IdentityJsonSerialyzer;
import org.restoran.service.parser.jackson.ItemOrderBeanDeserialyze;
import org.restoran.service.parser.jackson.ItemOrderBeanSerializer;
import org.restoran.service.parser.jackson.TableRefDeserializer;

import javax.persistence.*;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Null;
import java.util.*;

/**
 * Simple JavaBean domain object that represent <code>Order<code/> entity.
 *
 * @author Snisar Bogdan.
 */

@Entity
@javax.persistence.Table(name = "ORDERS")
public class Order extends BaseEntity {

    public Order() {
        this.openDate = new Date();
        this.status = OrderStatus.OPENED;
    }

    public Order(Integer orderId) {
        this();
        this.setId(orderId);
    }

    public Order(Integer id, Date openDate, Date closeDate, OrderStatus status) {
        super(id);
        this.openDate = openDate;
        this.closeDate = closeDate;
        this.status = status;
    }

    @JsonSerialize (using = IdentityJsonSerialyzer.class)
    @JsonDeserialize (using = TableRefDeserializer.class)
    @JsonProperty("deskId")
	@OneToOne(mappedBy="order", fetch=FetchType.LAZY, cascade = CascadeType.PERSIST)
	private Table table;

    @Column(name = "OPEN_DATE", nullable = false)
    @Temporal(TemporalType.DATE)
    @NotNull
    private Date openDate;

    @Column(name = "CLOSE_DATE", nullable = true)
    @Temporal(TemporalType.DATE)
    @Null
    private Date closeDate;

    @Column(name = "ORDER_STATUS", nullable = false)
    @Enumerated(EnumType.STRING)
    @NotNull
    private OrderStatus status;

    public Set<ItemOrder> getItems() {
        return items;
    }

    public void setItems(Set<ItemOrder> items) {
        this.items = items;
    }

    @JsonDeserialize(contentUsing = ItemOrderBeanDeserialyze.class)
    @JsonSerialize(contentUsing = ItemOrderBeanSerializer.class)
    @OneToMany(fetch = FetchType.EAGER,
            mappedBy = "pk.order",
            cascade=CascadeType.ALL,
            orphanRemoval = true)
    private Set<ItemOrder> items = new HashSet<>();

    public void addTable(Table tab) {
        this.setTable(tab);
        tab.setOrder(this);
    }

    public Date getOpenDate() {
        return openDate;
    }

    public void setOpenDate(Date openDate) {
        this.openDate = openDate;
    }

    public Date getCloseDate() {
        return closeDate;
    }

    public void setCloseDate(Date closeDate) {
        this.closeDate = closeDate;
    }

    public void addItemOrder(ItemOrder iwo) {
        items.add(iwo);
        iwo.setOrder(this);
    }

    public boolean hasItem(Item item) {
        for (ItemOrder oi : items) {
            if(oi.getPk().getItem().equals(item)) return true;
        }
        return false;
    }

    @JsonProperty("orderId")
    public void setOrderId(Integer id) {
        this.setId(id);
    }

    @Override
    public String toString() {
        return "Order{id= " + getId() +
                ", openDate=" + openDate +
                ", closeDate=" + closeDate +
                ", items=" + items
                + ", tableId " + ((table==null) ? "null" : table.getId());
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof Order)) return false;

        Order order = (Order) o;

        if (closeDate != null ? !closeDate.equals(order.closeDate) : order.closeDate != null) return false;
        if (items != null ? !items.equals(order.items) : order.items != null) return false;
        if (openDate != null ? !openDate.equals(order.openDate) : order.openDate != null) return false;

        return true;
    }

    @Override
    public int hashCode() {
        int result = openDate != null ? openDate.hashCode() : 0;
        result = 31 * result + (closeDate != null ? closeDate.hashCode() : 0);
        result = 31 * result + (items != null ? items.hashCode() : 0);
        return result;
    }

	public Table getTable() {
		return table;
	}

	public void setTable(Table table) {
		this.table = table;
	}

    public OrderStatus getStatus() {
        return status;
    }

    public void setStatus(OrderStatus status) {
        this.status = status;
    }
}
